package com.qizhan100.qtools.weixin;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;

import javax.xml.parsers.ParserConfigurationException;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.xml.sax.SAXException;

import com.qizhan100.qtools.common.MD5;
import com.qizhan100.qtools.common.StringUtils;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
import com.thoughtworks.xstream.io.xml.XppDriver;

/**
 * @版权：厦门奇站网络科技有限公司 版权所有 (c) 2015
 * @author zhuanglt
 * @version Revision 2.0.0
 * @email:longteng1988@qq.com
 * @see:
 * @创建日期：2017-6-23
 * @功能说明：微信支付工具类
 */
public class WxPayTool {
    public static String create_nonce_str() {
        return UUID.randomUUID().toString();
    }
    
    public static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }
    
    public static String create_nonce_str(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }
    
    /**
     * @param map
     * @return
     * @author:zhuanglt
     * @email:longteng1988@qq.com
     * @创建日期:2016-9-8
     * @功能说明：map转换为签名字符串
     */
    public static String mapToPlainStr(Map<String, String> map) {
        StringBuilder builder = new StringBuilder();
        
        List<String> exclude = new ArrayList<String>();
        exclude.add("sign");
        
        Object[] keys = map.keySet().toArray();
        Arrays.sort(keys);
        for (Object key : keys) {
            String value = map.get(key);
            if (!exclude.contains(key) && value != null && StringUtils.isNotBlank(value.toString())) {
                builder.append(key);
                builder.append("=");
                builder.append(value == null ? "" : value.toString());
                builder.append("&");
            }
        }
        return builder.length() > 0 ? builder.substring(0, builder.length() - 1) : builder.toString();
    }
    
    public static Map<String, String> xmlToMap(String xmlString) throws ParserConfigurationException, IOException, SAXException {
        
        Map<String, String> map = new HashMap<String, String>();
        Document doc = null;
        try {
            doc = DocumentHelper.parseText(xmlString); // 将字符串转为XML
            Element rootElt = doc.getRootElement(); // 获取根节点
            @SuppressWarnings("unchecked")
            List<Element> list = rootElt.elements();// 获取根节点下所有节点
            for (Element element : list) { // 遍历节点
                map.put(element.getName(), element.getText()); // 节点的name为map的key，text为map的value
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
        
    }
    
    public static <T> HashMap<String, Field> fieldMap(Class<T> clazz) {
        HashMap<String, Field> map = new HashMap<String, Field>();
        Class<T> c = clazz;
        Field[] fields = c.getDeclaredFields();
        for (Field f : fields) {
            map.put(f.getName(), f);
        }
        // super
        Class sup = c.getSuperclass();
        Field[] superFields = sup.getDeclaredFields();
        for (Field f : superFields) {
            map.put(f.getName(), f);
        }
        return map;
    }
    
    public static <T> String ObjectToPlainStr(Class<T> clazz, Object target, String[] excludeField) throws Exception {
        StringBuilder builder = new StringBuilder();
        
        HashMap<String, Field> map = fieldMap(clazz);
        Object[] keys = map.keySet().toArray();
        Arrays.sort(keys);
        
        List<String> exclude = new ArrayList<String>(Arrays.asList(excludeField));
        exclude.add("sign");
        
        for (Object key : keys) {
            Field field = map.get(key);
            field.setAccessible(true);
            Object value = field.get(target);
            if (!exclude.contains(field.getName()) && value != null && StringUtils.isNotBlank(value.toString())) {
                builder.append(key);
                builder.append("=");
                builder.append(value == null ? "" : value.toString());
                builder.append("&");
            }
        }
        return builder.length() > 0 ? builder.substring(0, builder.length() - 1) : builder.toString();
    }
    
    public static String makeSign(String plainStr, String apiKey) {
        // 在string后加入API KEY
        plainStr += "&key=" + apiKey;
        
        // 所有字符转为大写
        return MD5.Encode(plainStr).toUpperCase();
    }
    
    public static String objectToXml(Class clazz, Object obj) {
        XStream xstream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));
        xstream.alias("xml", clazz);
        return xstream.toXML(obj);
    }
    
    public static <T> String objectToXml(Class<T> clazz, Object target, String[] excludeField) throws Exception {
        HashMap<String, Field> map = fieldMap(clazz);
        Object[] keys = map.keySet().toArray();
        
        List<String> exclude = new ArrayList<String>(Arrays.asList(excludeField));
        // exclude.add("sign");
        
        StringBuilder xml = new StringBuilder("<xml>");
        for (Object key : keys) {
            Field field = map.get(key);
            field.setAccessible(true);
            Object value = field.get(target);
            if (!exclude.contains(field.getName()) && value != null && StringUtils.isNotBlank(value.toString())) {
                xml.append("<" + key + ">");
                xml.append("<![CDATA[" + value + "]]>");
                xml.append("</" + key + ">");
            }
        }
        xml.append("</xml>");
        return xml.toString();
    }
}
